#include <gtest/gtest.h>
#include "Poller/SelectWrap.h"
#include <unistd.h>
#include <sys/socket.h>

using namespace toolkit;

class SelectWrapTest : public testing::Test {
protected:
    void SetUp() override {
        if (pipe(pipe_fd) == -1) {
            throw std::runtime_error("Create pipe failed");
        }
    }

    void TearDown() override {
        close(pipe_fd[0]);
        close(pipe_fd[1]);
    }

    int pipe_fd[2];
};

TEST_F(SelectWrapTest, FdSetBasicOperations) {
    FdSet fdset;
    fdset.fdZero();
    
    // 测试fdSet和isSet
    fdset.fdSet(pipe_fd[0]);
    EXPECT_TRUE(fdset.isSet(pipe_fd[0]));
    
    // 测试fdClr
    fdset.fdClr(pipe_fd[0]);
    EXPECT_FALSE(fdset.isSet(pipe_fd[0]));
}

TEST_F(SelectWrapTest, SelectReadable) {
    FdSet read_fds;
    read_fds.fdZero();
    read_fds.fdSet(pipe_fd[0]);
    
    // 写入数据使管道可读
    const char data = 'A';
    write(pipe_fd[1], &data, 1);
    
    timeval tv = {0, 0}; // 不等待
    int ret = zl_select(pipe_fd[0] + 1, &read_fds, nullptr, nullptr, &tv);
    
    EXPECT_EQ(ret, 1);
    EXPECT_TRUE(read_fds.isSet(pipe_fd[0]));
}

TEST_F(SelectWrapTest, SelectWritable) {
    FdSet write_fds;
    write_fds.fdZero();
    write_fds.fdSet(pipe_fd[1]);
    
    timeval tv = {0, 0}; // 不等待
    int ret = zl_select(pipe_fd[1] + 1, nullptr, &write_fds, nullptr, &tv);
    
    EXPECT_EQ(ret, 1);
    EXPECT_TRUE(write_fds.isSet(pipe_fd[1]));
}

TEST_F(SelectWrapTest, SelectTimeout) {
    FdSet read_fds;
    read_fds.fdZero();
    read_fds.fdSet(pipe_fd[0]);
    
    timeval tv = {0, 1000}; // 1ms超时
    int ret = zl_select(pipe_fd[0] + 1, &read_fds, nullptr, nullptr, &tv);
    
    EXPECT_EQ(ret, 0); // 超时应返回0
}

TEST_F(SelectWrapTest, SelectMultipleFds) {
    int sock_pair[2];
    socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair);
    
    FdSet read_fds;
    read_fds.fdZero();
    read_fds.fdSet(pipe_fd[0]);
    read_fds.fdSet(sock_pair[0]);
    
    // 只写入一个fd
    const char data = 'A';
    write(pipe_fd[1], &data, 1);
    
    timeval tv = {0, 0};
    int ret = zl_select(std::max(pipe_fd[0], sock_pair[0]) + 1, &read_fds, nullptr, nullptr, &tv);
    
    EXPECT_EQ(ret, 1);
    EXPECT_TRUE(read_fds.isSet(pipe_fd[0]));
    EXPECT_FALSE(read_fds.isSet(sock_pair[0]));
    
    close(sock_pair[0]);
    close(sock_pair[1]);
}